/**
 * 地图工具函数模块
 * @description 提供地图操作相关的工具方法，包括坐标转换、几何计算、视角控制等
 */

import { ref } from 'vue';

/**
 * 地图工具类
 * @class MapUtils
 */
export class MapUtils {
  constructor(mapEngine) {
    this.mapEngine = mapEngine;
  }

  /**
   * 获取地图实例
   * @private
   * @returns {mars3d.Map|null} 地图实例
   */
  _getMap() {
    return this.mapEngine?.getInstance() || null;
  }

  /**
   * 飞行到指定点位
   * @param {number} lng - 经度
   * @param {number} lat - 纬度
   * @param {Object} options - 飞行选项
   * @param {number} options.duration - 飞行持续时间（秒）
   * @param {number} options.alt - 高度
   * @param {number} options.heading - 方向角
   * @param {number} options.pitch - 俯仰角
   * @param {number} options.roll - 翻滚角
   * @returns {Promise} 飞行完成Promise
   */
  flyToPoint(lng, lat, options = {}) {
    const map = this._getMap();
    if (!map) return Promise.reject(new Error('Map not initialized'));

    const defaultOptions = {
      duration: 1.0,
      alt: undefined,
      heading: undefined,
      pitch: undefined,
      roll: undefined
    };
    
    const flyOptions = { ...defaultOptions, ...options };
    
    const centerOptions = {
      lng: Number(lng),
      lat: Number(lat),
      ...(flyOptions.alt !== undefined && { alt: flyOptions.alt }),
      ...(flyOptions.heading !== undefined && { heading: flyOptions.heading }),
      ...(flyOptions.pitch !== undefined && { pitch: flyOptions.pitch }),
      ...(flyOptions.roll !== undefined && { roll: flyOptions.roll })
    };

    return new Promise((resolve, reject) => {
      try {
        map.centerAt(centerOptions, { 
          duration: flyOptions.duration,
          complete: resolve
        });
      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * 飞行到指定范围
   * @param {Object} extent - 范围对象
   * @param {number} extent.xmin - 最小经度
   * @param {number} extent.ymin - 最小纬度
   * @param {number} extent.xmax - 最大经度
   * @param {number} extent.ymax - 最大纬度
   * @param {Object} options - 飞行选项
   * @param {number} options.duration - 飞行持续时间
   * @param {number} options.radius - 视角半径
   * @returns {Promise} 飞行完成Promise
   */
  flyToExtent(extent, options = {}) {
    const map = this._getMap();
    if (!map) return Promise.reject(new Error('Map not initialized'));

    const defaultOptions = { 
      duration: 1.0,
      radius: undefined
    };
    const flyOptions = { ...defaultOptions, ...options };

    return new Promise((resolve, reject) => {
      try {
        map.flyToExtent(extent, {
          ...flyOptions,
          complete: resolve
        });
      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * 设置地图视角
   * @param {Object} viewpoint - 视角参数
   * @param {number} viewpoint.lng - 经度
   * @param {number} viewpoint.lat - 纬度
   * @param {number} viewpoint.alt - 高度
   * @param {number} viewpoint.heading - 方向角
   * @param {number} viewpoint.pitch - 俯仰角
   * @param {Object} options - 动画选项
   * @returns {Promise} 设置完成Promise
   */
  setView(viewpoint, options = {}) {
    const map = this._getMap();
    if (!map) return Promise.reject(new Error('Map not initialized'));

    const defaultOptions = { duration: 1.0 };
    const animationOptions = { ...defaultOptions, ...options };
    
    return new Promise((resolve, reject) => {
      try {
        map.centerAt(viewpoint, {
          ...animationOptions,
          complete: resolve
        });
      } catch (error) {
        reject(error);
      }
    });
  }

  /**
   * 获取当前地图中心点
   * @returns {Object|null} 中心点坐标 {lng, lat, alt, heading, pitch, roll}
   */
  getCurrentCenter() {
    const map = this._getMap();
    if (!map) return null;
    
    try {
      const camera = map.camera;
      const cartographic = mars3d.Cartographic.fromCartesian(camera.position);
      
      return {
        lng: mars3d.Math.toDegrees(cartographic.longitude),
        lat: mars3d.Math.toDegrees(cartographic.latitude),
        alt: cartographic.height,
        heading: mars3d.Math.toDegrees(camera.heading),
        pitch: mars3d.Math.toDegrees(camera.pitch),
        roll: mars3d.Math.toDegrees(camera.roll)
      };
    } catch (error) {
      console.error('Failed to get current center:', error);
      return null;
    }
  }

  /**
   * 获取地图边界
   * @returns {Object|null} 地图边界 {west, south, east, north}
   */
  getMapBounds() {
    const map = this._getMap();
    if (!map) return null;
    
    try {
      const rectangle = map.camera.computeViewRectangle();
      
      return {
        west: mars3d.Math.toDegrees(rectangle.west),
        south: mars3d.Math.toDegrees(rectangle.south),
        east: mars3d.Math.toDegrees(rectangle.east),
        north: mars3d.Math.toDegrees(rectangle.north)
      };
    } catch (error) {
      console.error('Failed to get map bounds:', error);
      return null;
    }
  }

  /**
   * 屏幕坐标转世界坐标
   * @param {Object} screenPosition - 屏幕坐标 {x, y}
   * @returns {Object|null} 世界坐标 {lng, lat, alt} 或 null
   */
  screenToWorld(screenPosition) {
    const map = this._getMap();
    if (!map) return null;

    try {
      const { x, y } = screenPosition;
      const cartesian = map.camera.pickEllipsoid(
        new Cesium.Cartesian2(x, y),
        map.scene.globe.ellipsoid
      );

      if (!cartesian) return null;

      const cartographic = mars3d.Cartographic.fromCartesian(cartesian);
      
      return {
        lng: mars3d.Math.toDegrees(cartographic.longitude),
        lat: mars3d.Math.toDegrees(cartographic.latitude),
        alt: cartographic.height
      };
    } catch (error) {
      console.error('Failed to convert screen to world coordinates:', error);
      return null;
    }
  }

  /**
   * 世界坐标转屏幕坐标
   * @param {Object} worldPosition - 世界坐标 {lng, lat, alt}
   * @returns {Object|null} 屏幕坐标 {x, y} 或 null
   */
  worldToScreen(worldPosition) {
    const map = this._getMap();
    if (!map) return null;

    try {
      const { lng, lat, alt = 0 } = worldPosition;
      const cartesian = Cesium.Cartesian3.fromDegrees(lng, lat, alt);
      const screenPosition = Cesium.SceneTransforms.wgs84ToWindowCoordinates(
        map.scene,
        cartesian
      );

      return screenPosition ? {
        x: screenPosition.x,
        y: screenPosition.y
      } : null;
    } catch (error) {
      console.error('Failed to convert world to screen coordinates:', error);
      return null;
    }
  }

  /**
   * 计算两点间距离
   * @param {Object} point1 - 起点 {lng, lat, alt}
   * @param {Object} point2 - 终点 {lng, lat, alt}
   * @param {string} unit - 单位 ('m' | 'km' | 'ft' | 'mi')
   * @returns {number|null} 距离值
   */
  measureDistance(point1, point2, unit = 'm') {
    try {
      const pos1 = Cesium.Cartesian3.fromDegrees(
        point1.lng, 
        point1.lat, 
        point1.alt || 0
      );
      const pos2 = Cesium.Cartesian3.fromDegrees(
        point2.lng, 
        point2.lat, 
        point2.alt || 0
      );

      const distance = Cesium.Cartesian3.distance(pos1, pos2);
      
      return this._convertDistance(distance, unit);
    } catch (error) {
      console.error('Failed to measure distance:', error);
      return null;
    }
  }

  /**
   * 计算多边形面积
   * @param {Array} coordinates - 坐标数组 [{lng, lat, alt}, ...]
   * @param {string} unit - 单位 ('m²' | 'km²' | 'ft²' | 'acre')
   * @returns {number|null} 面积值
   */
  calculateArea(coordinates, unit = 'm²') {
    if (!coordinates || coordinates.length < 3) return null;

    try {
      const positions = coordinates.map(coord => 
        Cesium.Cartesian3.fromDegrees(coord.lng, coord.lat, coord.alt || 0)
      );

      // 使用球面面积计算
      const area = mars3d.MeasureUtil.getAreaBySphere(positions);
      
      return this._convertArea(area, unit);
    } catch (error) {
      console.error('Failed to calculate area:', error);
      return null;
    }
  }

  /**
   * 判断点是否在多边形内
   * @param {Object} point - 点坐标 {lng, lat}
   * @param {Array} polygon - 多边形坐标数组 [{lng, lat}, ...]
   * @returns {boolean} 是否在多边形内
   */
  isPointInPolygon(point, polygon) {
    if (!point || !polygon || polygon.length < 3) return false;

    try {
      const { lng, lat } = point;
      let inside = false;
      
      for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
        const xi = polygon[i].lng;
        const yi = polygon[i].lat;
        const xj = polygon[j].lng;
        const yj = polygon[j].lat;
        
        if (((yi > lat) !== (yj > lat)) && 
            (lng < (xj - xi) * (lat - yi) / (yj - yi) + xi)) {
          inside = !inside;
        }
      }
      
      return inside;
    } catch (error) {
      console.error('Failed to check point in polygon:', error);
      return false;
    }
  }

  /**
   * 创建热力图数据
   * @param {Array} points - 数据点数组 [{lng, lat, value}, ...]
   * @param {Object} options - 热力图选项
   * @param {number} options.radius - 影响半径
   * @param {number} options.maxValue - 最大值
   * @param {Object} options.gradient - 颜色渐变
   * @returns {Array} 处理后的热力图数据
   */
  createHeatmapData(points, options = {}) {
    if (!points || points.length === 0) return [];

    const {
      radius = 50,
      maxValue = null
    } = options;

    try {
      // 计算最大值
      const max = maxValue || Math.max(...points.map(p => p.value || 1));
      
      // 标准化数据
      const normalizedData = points.map(point => ({
        lng: point.lng,
        lat: point.lat,
        value: (point.value || 1) / max,
        radius: point.radius || radius
      }));

      return normalizedData;
    } catch (error) {
      console.error('Failed to create heatmap data:', error);
      return [];
    }
  }

  /**
   * 格式化坐标
   * @param {Object} coord - 坐标对象 {lng, lat, alt}
   * @param {string} format - 格式类型 ('decimal' | 'dms' | 'utm')
   * @param {number} precision - 精度
   * @returns {string} 格式化后的坐标字符串
   */
  formatCoordinates(coord, format = 'decimal', precision = 6) {
    if (!coord || typeof coord.lng !== 'number' || typeof coord.lat !== 'number') {
      return '';
    }

    try {
      switch (format.toLowerCase()) {
        case 'decimal':
          return this._formatDecimal(coord, precision);
        case 'dms':
          return this._formatDMS(coord);
        case 'utm':
          return this._formatUTM(coord);
        default:
          return this._formatDecimal(coord, precision);
      }
    } catch (error) {
      console.error('Failed to format coordinates:', error);
      return '';
    }
  }

  /**
   * 格式化十进制坐标
   * @private
   * @param {Object} coord - 坐标对象
   * @param {number} precision - 精度
   * @returns {string} 格式化字符串
   */
  _formatDecimal(coord, precision) {
    const lng = coord.lng.toFixed(precision);
    const lat = coord.lat.toFixed(precision);
    const alt = coord.alt ? coord.alt.toFixed(2) : '0.00';
    
    return `经度: ${lng}°, 纬度: ${lat}°, 高度: ${alt}m`;
  }

  /**
   * 格式化度分秒坐标
   * @private
   * @param {Object} coord - 坐标对象
   * @returns {string} 格式化字符串
   */
  _formatDMS(coord) {
    const lngDMS = this._toDMS(coord.lng, 'lng');
    const latDMS = this._toDMS(coord.lat, 'lat');
    const alt = coord.alt ? coord.alt.toFixed(2) : '0.00';
    
    return `${lngDMS}, ${latDMS}, 高度: ${alt}m`;
  }

  /**
   * 转换为度分秒格式
   * @private
   * @param {number} decimal - 十进制度数
   * @param {string} type - 类型 ('lng' | 'lat')
   * @returns {string} 度分秒字符串
   */
  _toDMS(decimal, type) {
    const absolute = Math.abs(decimal);
    const degrees = Math.floor(absolute);
    const minutes = Math.floor((absolute - degrees) * 60);
    const seconds = ((absolute - degrees - minutes / 60) * 3600).toFixed(2);
    
    const direction = type === 'lng' 
      ? (decimal >= 0 ? 'E' : 'W')
      : (decimal >= 0 ? 'N' : 'S');
    
    return `${degrees}°${minutes}'${seconds}"${direction}`;
  }

  /**
   * 格式化UTM坐标
   * @private
   * @param {Object} coord - 坐标对象
   * @returns {string} UTM格式字符串
   */
  _formatUTM(coord) {
    // 简化的UTM转换，实际项目中可能需要更精确的转换库
    const zone = Math.floor((coord.lng + 180) / 6) + 1;
    const hemisphere = coord.lat >= 0 ? 'N' : 'S';
    
    return `UTM Zone: ${zone}${hemisphere}, 经度: ${coord.lng.toFixed(6)}°, 纬度: ${coord.lat.toFixed(6)}°`;
  }

  /**
   * 转换距离单位
   * @private
   * @param {number} distance - 距离（米）
   * @param {string} unit - 目标单位
   * @returns {number} 转换后的距离
   */
  _convertDistance(distance, unit) {
    switch (unit.toLowerCase()) {
      case 'm':
        return distance;
      case 'km':
        return distance / 1000;
      case 'ft':
        return distance * 3.28084;
      case 'mi':
        return distance / 1609.344;
      default:
        return distance;
    }
  }

  /**
   * 转换面积单位
   * @private
   * @param {number} area - 面积（平方米）
   * @param {string} unit - 目标单位
   * @returns {number} 转换后的面积
   */
  _convertArea(area, unit) {
    switch (unit.toLowerCase()) {
      case 'm²':
        return area;
      case 'km²':
        return area / 1000000;
      case 'ft²':
        return area * 10.7639;
      case 'acre':
        return area / 4046.86;
      default:
        return area;
    }
  }

  /**
   * 计算地图分辨率
   * @returns {number|null} 当前地图分辨率（米/像素）
   */
  getMapResolution() {
    const map = this._getMap();
    if (!map) return null;

    try {
      const scene = map.scene;
      const canvas = scene.canvas;
      
      // 获取画布中心点
      const centerX = canvas.clientWidth / 2;
      const centerY = canvas.clientHeight / 2;
      
      // 获取相邻像素的世界坐标
      const centerWorld = this.screenToWorld({ x: centerX, y: centerY });
      const rightWorld = this.screenToWorld({ x: centerX + 1, y: centerY });
      
      if (!centerWorld || !rightWorld) return null;
      
      // 计算分辨率
      const resolution = this.measureDistance(centerWorld, rightWorld);
      return resolution;
    } catch (error) {
      console.error('Failed to get map resolution:', error);
      return null;
    }
  }

  /**
   * 获取地图缩放级别
   * @returns {number|null} 当前缩放级别
   */
  getZoomLevel() {
    const map = this._getMap();
    if (!map) return null;

    try {
      const camera = map.camera;
      const height = camera.positionCartographic.height;
      
      // 根据相机高度估算缩放级别
      const zoomLevel = Math.round(Math.log2(40075016.686 / height * 256 / 512));
      return Math.max(0, Math.min(22, zoomLevel));
    } catch (error) {
      console.error('Failed to get zoom level:', error);
      return null;
    }
  }

  /**
   * 创建边界框
   * @param {Array} coordinates - 坐标数组 [{lng, lat}, ...]
   * @returns {Object|null} 边界框 {minX, minY, maxX, maxY}
   */
  createBoundingBox(coordinates) {
    if (!coordinates || coordinates.length === 0) return null;

    try {
      let minX = Infinity, minY = Infinity;
      let maxX = -Infinity, maxY = -Infinity;

      coordinates.forEach(coord => {
        minX = Math.min(minX, coord.lng);
        minY = Math.min(minY, coord.lat);
        maxX = Math.max(maxX, coord.lng);
        maxY = Math.max(maxY, coord.lat);
      });

      return { minX, minY, maxX, maxY };
    } catch (error) {
      console.error('Failed to create bounding box:', error);
      return null;
    }
  }

  /**
   * 获取地图统计信息
   * @returns {Object} 统计信息
   */
  getMapStatistics() {
    const map = this._getMap();
    if (!map) return null;

    try {
      const center = this.getCurrentCenter();
      const bounds = this.getMapBounds();
      const resolution = this.getMapResolution();
      const zoomLevel = this.getZoomLevel();

      return {
        center,
        bounds,
        resolution,
        zoomLevel,
        layerCount: map.layerManager.layers.length,
        timestamp: new Date().toISOString()
      };
    } catch (error) {
      console.error('Failed to get map statistics:', error);
      return null;
    }
  }
}

/**
 * 地图工具组合函数
 * @param {Object} mapEngine - 地图引擎实例
 * @returns {Object} 地图工具API
 */
export function useMapUtils(mapEngine) {
  const utils = ref(null);

  /**
   * 初始化地图工具
   */
  const initUtils = () => {
    utils.value = new MapUtils(mapEngine);
    return utils.value;
  };

  /**
   * 获取工具实例
   */
  const getUtils = () => utils.value;

  /**
   * 销毁工具
   */
  const destroy = () => {
    if (utils.value) {
      utils.value = null;
    }
  };

  return {
    utils,
    initUtils,
    getUtils,
    destroy
  };
}
